package com.gotokeep.keep.composition.demo.renderer;

import android.content.Context;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.util.Log;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

/**
 * @author xana/cuixianming
 * @version 1.0
 * @since 2018-04-28 09:50
 */
public class TransitionRender implements Renderer {
    private int mProgramObject;
    private int mWidth;
    private int mHeight;
    private float videoSize[];
    private FloatBuffer mVertices;
    private ShortBuffer mTexCoords;
    private Context mContext;
    private int texIds[];
    private float alpha;
    private int transitionDurationMs = 1000;
    private static String TAG = "TransitionRender";
    private final float[] mVerticesData = {-1f, -1f, 0, 1f, -1f, 0, -1f, 1f, 0, 1f, 1f, 0};
    private final short[] mTexCoordsData = {0, 1, 1, 1, 0, 0, 1, 0};

    public TransitionRender(Context mContext) {
        this.mContext = mContext;

        mVertices = ByteBuffer.allocateDirect(mVerticesData.length * 4)
                .order(ByteOrder.nativeOrder()).asFloatBuffer();
        mVertices.put(mVerticesData).position(0);

        mTexCoords = ByteBuffer.allocateDirect(mTexCoordsData.length * 2)
                .order(ByteOrder.nativeOrder()).asShortBuffer();
        mTexCoords.put(mTexCoordsData).position(0);
    }

    public void setViewport(int width, int height) {
        mWidth = width;
        mHeight = height;
    }

    public void setVideoSize(int width, int height) {
        videoSize = new float[]{(float) width / mWidth, (float) height / mHeight};
    }

    @Override
    public void onInit(int... inputTexId) {
        texIds = inputTexId;
        comipleAndLinkProgram();

        GLES20.glClearColor(1f, 0, 0, 0f);
    }

    @Override
    public void onRelease() {
        if (mProgramObject >= 0) {
            GLES20.glDeleteProgram(mProgramObject);
        }
    }

    @Override
    public void onDrawFrame() {
        GLES20.glViewport(0, 0, mWidth, mHeight);

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
        GLES20.glUseProgram(mProgramObject);
        GLES20.glEnable(GLES20.GL_BLEND);

        GLES20.glVertexAttribPointer(0, 3, GLES20.GL_FLOAT, false, 0, mVertices);
        GLES20.glEnableVertexAttribArray(0);
        GLES20.glVertexAttribPointer(1, 2, GLES20.GL_SHORT, false, 0, mTexCoords);
        GLES20.glEnableVertexAttribArray(1);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texIds[0]);
        int loc = GLES20.glGetUniformLocation(mProgramObject, "texture0");
        GLES20.glUniform1i(loc, 0);
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texIds[1]);
        loc = GLES20.glGetUniformLocation(mProgramObject, "texture1");
        GLES20.glUniform1i(loc, 1);
        loc = GLES20.glGetUniformLocation(mProgramObject, "alpha");
        GLES20.glUniform1f(loc, alpha);
//        GLES20.glUniform1f(mIntensityLocation, mIntensity);
//        GLES20.glUniform3fv(mFilterColorLocation, 1, FloatBuffer.wrap(mColor));
//        loc = GLES20.glGetUniformLocation(mProgramObject, "v_videoSize");
//        GLES20.glUniform2fv(loc, 1, FloatBuffer.wrap(videoSize));
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);

        Log.d(TAG, "onDrawFrame");
    }

    private int loadShader(int shaderType, String shaderSource) {
        int shader;
        int[] compiled = new int[1];
        // Create the shader object
        shader = GLES20.glCreateShader(shaderType);
        if (shader == 0)
            return 0;
        // Load the shader source
        GLES20.glShaderSource(shader, shaderSource);
        // Compile the shader
        GLES20.glCompileShader(shader);
        // Check the compile status
        GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
            GLES20.glDeleteShader(shader);
            return 0;
        }
        return shader;
    }

    private void comipleAndLinkProgram() {
        String vShaderStr = "attribute vec4 a_position;    \n"
                + "attribute vec2 a_texCoords; \n"
                + "varying vec2 v_texCoords; \n"
                + "void main()                  \n"
                + "{                            \n"
                + "   gl_Position = a_position;  \n"
                + "    v_texCoords = a_texCoords; \n"
                + "}                            \n";
        String fShaderStr = "\n" +
                "#extension GL_OES_EGL_image_external : require\n" +
                "precision mediump float;                     \n"
                + "uniform samplerExternalOES texture0; \n"
                + "uniform samplerExternalOES texture1; \n"
                + "uniform float alpha;\n"
                + "varying vec2 v_texCoords; \n"
                + "void main()                                  \n"
                + "{                                            \n" +
                "  vec4 color0 = texture2D(texture0, v_texCoords);\n" +
                "  vec4 color1 = texture2D(texture1, v_texCoords);\n"
                + "  gl_FragColor = mix(color0, color1, alpha);\n"
                + "}                                            \n";
        int vertexShader;
        int fragmentShader;
        int programObject;

        int[] linked = new int[1];
        // Load the vertex/fragment shaders
        vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vShaderStr);
        fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fShaderStr);
        // Create the program object
        programObject = GLES20.glCreateProgram();
        if (programObject == 0)
            return;
        GLES20.glAttachShader(programObject, vertexShader);
        GLES20.glAttachShader(programObject, fragmentShader);
        // Bind vPosition to attribute 0
        GLES20.glBindAttribLocation(programObject, 0, "a_position");
        GLES20.glBindAttribLocation(programObject, 1, "a_texCoords");
        // Link the program
        GLES20.glLinkProgram(programObject);
        // Check the link status
        GLES20.glGetProgramiv(programObject, GLES20.GL_LINK_STATUS, linked, 0);
        if (linked[0] == 0) {
            Log.e(TAG, "Error linking program:");
            Log.e(TAG, GLES20.glGetProgramInfoLog(programObject));
            GLES20.glDeleteProgram(programObject);
            return;
        }
        mProgramObject = programObject;
    }

    public void setTexId(int... texIds) {
        this.texIds = texIds;
    }

    public void setAlpha(float alpha) {
        this.alpha = alpha;
    }
}
